package com.guit.hrms.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.guit.hrms.dto.interview.ApplyOfferDTO;
import com.guit.hrms.dto.interview.AssignedInterviewDTO;
import com.guit.hrms.dto.interview.UpdateInterviewStatusDTO;
import com.guit.hrms.mapper.*;
import com.guit.hrms.po.Employee;
import com.guit.hrms.po.ToEmail;
import com.guit.hrms.po.interview.Interview;
import com.guit.hrms.po.interview.InterviewSituation;
import com.guit.hrms.po.interview.Interviewee;
import com.guit.hrms.po.interview.Offer;
import com.guit.hrms.po.utilsPO.PageBean;
import com.guit.hrms.service.IntervieweeService;
import com.guit.hrms.utils.EmailUtil;
import com.guit.hrms.utils.JwtUtil;
import com.guit.hrms.utils.ThreadLocalUtil;
import com.guit.hrms.vo.IntervieweeVO;
import com.guit.hrms.vo.OfferVO;
import com.guit.hrms.vo.recruitmentVO.PlanDeptJobVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class IntervieweeServiceImpl implements IntervieweeService {
    @Autowired
    private IntervieweeMapper intervieweeMapper;
    @Autowired
    private InterviewMapper interviewMapper;
    @Autowired
    private RecruitmentMapper recruitmentMapper;
    @Autowired
    private EmailUtil emailUtil;
    @Autowired
    private OnboardingMapper onboardingMapper;
    @Value("${spring.mail.username1}")
    private String username1;
    @Autowired
    private QueryMapper queryMapper;

    /**
     * 根据应聘者id查找对应的简历
     *
     * @param id 应聘者id
     * @return 简历
     */
    @Override
    @Transactional
    public Interviewee findResumeById(Integer id) {
        return intervieweeMapper.getIntervieweeById(id);
    }

    /**
     * 应聘者上传简历
     *
     * @param interviewee 应聘者信息
     * @return 结果
     */
    @Override
    public Integer uploadResume(Interviewee interviewee) {
        Interviewee interviewee1 = intervieweeMapper.selectBlacklistIntervieweeByIdentificationNumber(interviewee.getIdentificationNumber());
        if (interviewee1 != null) {
            throw new RuntimeException("您已被拉入黑名单，无法上传简历");
        }
        interviewee1 = intervieweeMapper.selectRepeatInterviewee(interviewee);
        if (interviewee1 != null) {
            throw new RuntimeException("您已上传过信息应聘该岗位，无法再次上传");
        }
        Integer type = recruitmentMapper.getPlanTypeByPlanId(interviewee.getPlanId());
        if (type == null) {
            return 0;
        }
        PlanDeptJobVO planDeptJobVO = null;
        if (type == 1) {
            planDeptJobVO = recruitmentMapper.getPlanDeptJob(interviewee.getPlanId(), interviewee.getDeptId(), interviewee.getPositionNumber());
        } else if (type == 2) {
            planDeptJobVO = recruitmentMapper.getPlanAcademyJob(interviewee.getPlanId(), interviewee.getDeptId(), interviewee.getPositionNumber());
        } else {
            return intervieweeMapper.uploadResume(interviewee);
        }
        if (planDeptJobVO != null) {
            return intervieweeMapper.uploadResume(interviewee);
        } else {
            return 0;
        }
    }

    /**
     * 查询应聘者信息
     *
     * @param page           页码
     * @param pageSize       页大小
     * @param planId         招聘计划id
     * @param deptId         应聘部门id
     * @param positionNumber 应聘岗位编号
     * @return 应聘者信息
     */
    @Override
    public PageBean getInterviewee(Integer page, Integer pageSize, Integer planId, String deptId, String positionNumber) {
        PageHelper.startPage(page, pageSize);
        List<IntervieweeVO> interviewees = intervieweeMapper.getInterviewee(planId, deptId, positionNumber);
        List<IntervieweeVO> intervieweeVOList = new ArrayList<>();
        String employeeId = null;
        for (IntervieweeVO intervieweeVO : interviewees) {
            employeeId = queryMapper.getByIntervieweeId(intervieweeVO.getId());
            intervieweeVO.setEmployeeId(employeeId);
            intervieweeVOList.add(intervieweeVO);
        }
        BeanUtils.copyProperties(intervieweeVOList, interviewees);
        Page<IntervieweeVO> p = (Page<IntervieweeVO>) interviewees;
        return new PageBean(p.getTotal(), p.getResult());
    }

    /**
     * 为应聘者分配面试安排
     *
     * @param assignedInterviewDTO 面试安排情况
     * @return Result
     */
    @Override
    @Transactional
    public Integer assignedInterviewForInterviewee(AssignedInterviewDTO assignedInterviewDTO) {
        InterviewSituation interviewSituation = new InterviewSituation();
        interviewSituation.setInterviewId(assignedInterviewDTO.getInterviewId());
        Integer result = 0;
        List<String> emails = new ArrayList<>();
        Interviewee interviewee = null;
        UpdateInterviewStatusDTO updateInterviewStatusDTO = new UpdateInterviewStatusDTO();
        updateInterviewStatusDTO.setInterviewStatus(1);
        for (Integer intervieweeId : assignedInterviewDTO.getIntervieweeIds()) {
            interviewee = intervieweeMapper.getIntervieweeById(intervieweeId);
            if (interviewee == null) {
                throw new RuntimeException("应聘者不存在");
            }
            interviewSituation.setIntervieweeId(intervieweeId);
            interviewSituation.setCreateTime(LocalDateTime.now());
            interviewSituation.setUpdateTime(LocalDateTime.now());
            if (interviewMapper.getInterviewSituations(interviewSituation.getInterviewId(), interviewSituation.getIntervieweeId()).isEmpty()) {
                result = interviewMapper.assignedInterviewForInterviewee(interviewSituation);
                if (result == 0) {
                    throw new RuntimeException("分配失败");
                }
                updateInterviewStatusDTO.setIntervieweeIds(new ArrayList<>());
                updateInterviewStatusDTO.getIntervieweeIds().add(intervieweeId);
                if (intervieweeMapper.updateInterviewStatus(updateInterviewStatusDTO) == 0) {
                    throw new RuntimeException("修改面试状态失败");
                }
                if (interviewMapper.updateInterviewNumber(interviewSituation.getInterviewId(), 1) == 0) {
                    throw new RuntimeException("增加面试人数失败");
                }
            } else {
                return 0;
            }
            emails.add(interviewee.getEmail());
        }
        ToEmail toEmail = new ToEmail();
        toEmail.setTos(emails.toArray(new String[0]));
        toEmail.setSubject(assignedInterviewDTO.getSubject());
        toEmail.setContent(assignedInterviewDTO.getText());
        emailUtil.sendSimpleEmail(toEmail);
        return 1;
    }

    /**
     * 取消应聘者的面试安排
     *
     * @param assignedInterviewDTO 面试安排情况
     * @return Result
     */
    @Override
    @Transactional
    public Integer cancelIntervieweesInterview(AssignedInterviewDTO assignedInterviewDTO) {
        InterviewSituation interviewSituation = new InterviewSituation();
        interviewSituation.setInterviewId(assignedInterviewDTO.getInterviewId());
        Integer result = 0;
        List<String> emails = new ArrayList<>();
        Interviewee interviewee = null;
        UpdateInterviewStatusDTO updateInterviewStatusDTO = new UpdateInterviewStatusDTO();
        updateInterviewStatusDTO.setInterviewStatus(0);
        for (Integer intervieweeId : assignedInterviewDTO.getIntervieweeIds()) {
            interviewee = intervieweeMapper.getIntervieweeById(intervieweeId);
            if (interviewee == null) {
                return 0;
            }
            interviewSituation.setIntervieweeId(intervieweeId);
            interviewSituation.setCreateTime(LocalDateTime.now());
            interviewSituation.setUpdateTime(LocalDateTime.now());
            if (!interviewMapper.getInterviewSituations(interviewSituation.getInterviewId(), interviewSituation.getIntervieweeId()).isEmpty()) {
                result = interviewMapper.cancelIntervieweesInterview(interviewSituation);
                if (result == 0) {
                    return 0;
                }
                updateInterviewStatusDTO.setIntervieweeIds(new ArrayList<>());
                updateInterviewStatusDTO.getIntervieweeIds().add(intervieweeId);
                if (intervieweeMapper.updateInterviewStatus(updateInterviewStatusDTO) == 0) {
                    throw new RuntimeException("修改面试状态失败");
                }
                if (interviewMapper.updateInterviewNumber(interviewSituation.getInterviewId(), -1) == 0) {
                    throw new RuntimeException("减少面试人数失败");
                }
            } else {
                return 0;
            }
            emails.add(interviewee.getEmail());
        }
        ToEmail toEmail = new ToEmail();
        toEmail.setTos(emails.toArray(new String[0]));
        toEmail.setSubject(assignedInterviewDTO.getSubject());
        toEmail.setContent(assignedInterviewDTO.getText());
        emailUtil.sendSimpleEmail(toEmail);
        return 1;
    }

    /**
     * 上传offer接受结果
     *
     * @param offerToken
     * @param result
     */
    @Override
    @Transactional
    public Integer uploadOfferAcceptResult(String offerToken, Integer result) {
        Map<String, Object> claims = null;
        try {
            claims = JwtUtil.parseToken(offerToken);
        } catch (Exception e) {
            throw new RuntimeException("解析token失败,该offerToken已过期或错误");
        }
        Integer intervieweeId = (Integer) claims.get("intervieweeId");
        Interviewee interviewee = intervieweeMapper.getIntervieweeById(intervieweeId);
        if (interviewee == null) {
            throw new RuntimeException("该应聘者不存在");
        }
        UpdateInterviewStatusDTO updateInterviewStatusDTO = new UpdateInterviewStatusDTO();
        List<Integer> intervieweeIds = new ArrayList<>();
        intervieweeIds.add(intervieweeId);
        updateInterviewStatusDTO.setIntervieweeIds(intervieweeIds);
        updateInterviewStatusDTO.setInterviewStatus(result == 1 ? 5 : 7);
        Integer r = intervieweeMapper.updateInterviewStatus(updateInterviewStatusDTO);
        if (r == 0) {
            throw new RuntimeException("修改应聘者面试状态失败");
        }
        if (result == 2) {
            r = onboardingMapper.deleteOnboardingByIntervieweeId(intervieweeId);
        }
        if (r == 0) {
            throw new RuntimeException("删除待入职信息失败");
        }
        r = intervieweeMapper.updateOfferTokenByResult(offerToken, result);
        if (r == 0) {
            throw new RuntimeException("已接受或拒绝offer，请勿重复操作");
        }
        return r;
    }

    /**
     * 获取offer结果
     *
     * @param page
     * @param pageSize
     * @param startTime
     * @param endTime
     * @param result
     * @return
     */
    @Override
    public PageBean getOfferResult(Integer page, Integer pageSize, LocalDateTime startTime, LocalDateTime endTime, Integer result) {
        PageHelper.startPage(page, pageSize);
        List<OfferVO> offerList = intervieweeMapper.getOfferResult(startTime, endTime, result);
        Interviewee interviewee = null;
        Employee employee = null;
        List<OfferVO> offerVOS = new ArrayList<>();
        for (OfferVO offerVO : offerList) {
            interviewee = intervieweeMapper.getIntervieweeById(offerVO.getIntervieweeId());
            offerVO.setIntervieweeName(interviewee == null ? null : interviewee.getName());
            employee = queryMapper.getById(offerVO.getApplicantId());
            offerVO.setApplicantName(employee == null ? null : employee.getUsername());
            employee = queryMapper.getById(offerVO.getApproverId());
            offerVO.setApproverName(employee == null ? null : employee.getUsername());
            offerVOS.add(offerVO);
        }
        offerList.clear();
        offerList.addAll(offerVOS);
        Page<OfferVO> p = (Page<OfferVO>) offerList;
        return new PageBean(p.getTotal(), p.getResult());
    }

    /**
     * 修改应聘者面试状态
     *
     * @param updateInterviewStatusDTO 面试状态信息
     * @return Result
     */
    @Override
    public Integer updateInterviewStatus(UpdateInterviewStatusDTO updateInterviewStatusDTO) {
        return intervieweeMapper.updateInterviewStatus(updateInterviewStatusDTO);
    }

    /**
     * 删除应聘者信息
     *
     * @param intervieweeIds 应聘者id
     * @return Result
     */
    @Override
    @Transactional
    public Integer deleteInterviewee(List<Integer> intervieweeIds) {
        Interviewee interviewee = null;
        List<Interview> interview = null;
        Integer result = 0;
        Integer result1 = 0;
        List<String> emails = new ArrayList<>();
        ToEmail toEmail = new ToEmail();
        for (Integer intervieweeId : intervieweeIds) {
            interviewee = intervieweeMapper.getIntervieweeById(intervieweeId);
            if (interviewee == null) {
                return 0;
            }
            interview = interviewMapper.getInterviewIdByIntervieweeId(intervieweeId);
            emails.add(interviewee.getEmail());
            if (!interview.isEmpty()) {
                for (Interview interview1 : interview) {
                    if (interview1.getStartTime().isAfter(LocalDateTime.now()) /*|| interview1.getStartTime().isEqual(LocalDateTime.now())*/) {
                        result1 = interviewMapper.updateInterviewNumber(interview1.getId(), -1);
                        if (result1 == 0) {
                            throw new RuntimeException("更新面试人数失败！");
                        }
                    } else {
                        result1 = 1;
                    }
                }
            } else {
                result1 = 1;
            }
            result = intervieweeMapper.deleteInterviewee(intervieweeId);
            if (result * result1 == 0) {
                throw new RuntimeException("删除失败");
            }
            toEmail.setTos(emails.toArray(new String[0]));
            toEmail.setSubject("应聘不通过通知");
            toEmail.setContent("很抱歉，您不符合我校的招聘要求......");
            emailUtil.sendSimpleEmail(toEmail);
            interviewMapper.deleteInterviewSituationByIntervieweeId(intervieweeId);
        }
        return result;
    }

    /**
     * 为应聘者申请offer
     *
     * @param applyOfferDTO offer信息
     * @return Result
     */
    @Override
    @Transactional
    public Integer applyOfferForInterviewee(ApplyOfferDTO applyOfferDTO) {
        // 1. 检查应聘者是否存在
        Interviewee interviewee = intervieweeMapper.getIntervieweeById(applyOfferDTO.getIntervieweeId());
        if (interviewee == null) {
            throw new RuntimeException("应聘者不存在");
        }
        // 2. 检查是否已经申请过offer
        Offer offer = intervieweeMapper.getOfferByIntervieweeId(applyOfferDTO.getIntervieweeId());
        if (offer != null) {
            throw new RuntimeException("该应聘者已申请offer");
        }
        // 3. 提前校验申请说明长度（数据库字段instructions最大长度为255）
        if (applyOfferDTO.getInstructions() != null && applyOfferDTO.getInstructions().length() > 255) {
            throw new RuntimeException("申请说明太长，请将申请说明控制在100字符以内");
        }

        // 4. 获取当前申请者的工号
        Map<String, Object> map = ThreadLocalUtil.get();
        String employeeId = map.get("employeeId").toString();

        Offer offer1 = new Offer();
        BeanUtils.copyProperties(applyOfferDTO, offer1);
        offer1.setApplicantId(employeeId);
        offer1.setCreateTime(LocalDateTime.now());
        offer1.setUpdateTime(LocalDateTime.now());

        int result = 0;
        try {
            result = intervieweeMapper.applyOfferForInterviewee(offer1);
        } catch (org.springframework.dao.DataIntegrityViolationException e) {
            if (e.getMessage() != null && e.getMessage().contains("Data truncation")) {
                throw new RuntimeException("申请说明太长，请将申请说明控制在255字符以内");
            }
            throw new RuntimeException("申请offer时发生数据库错误: " + e.getMessage());
        }

        int result1 = 0;
        if (result == 0) {
            return 0;
        } else {
            UpdateInterviewStatusDTO updateInterviewStatusDTO = new UpdateInterviewStatusDTO();
            updateInterviewStatusDTO.setIntervieweeIds(new ArrayList<>());
            updateInterviewStatusDTO.getIntervieweeIds().add(applyOfferDTO.getIntervieweeId());
            updateInterviewStatusDTO.setInterviewStatus(3);
            result1 = intervieweeMapper.updateInterviewStatus(updateInterviewStatusDTO);
        }

        if (result * result1 == 0) {
            throw new RuntimeException("操作失败，请检查输入信息是否正确");
        }
        return result * result1;
    }

    /**
     * 处理超时offer
     */
    @Override
    @Transactional
    public void checkExpiredOffersBatch() {
        int pageSize = 100;
        int offset = 0;
        Integer result = 0;
        boolean hasMore = true;

        while (hasMore) {
            List<Offer> offers = intervieweeMapper.checkExpiredOffersBatch(LocalDateTime.now(), pageSize, offset);
            List<Integer> ids = offers.stream()
                    .map(Offer::getId)
                    .toList();
            if (ids.isEmpty()) {
                hasMore = false;
            } else {
                List<Interviewee> interviewees = new ArrayList<>();
                Interviewee interviewee = null;
                List<String> errorMsg = new ArrayList<>();
                boolean hasError = false;
                // 批量更新状态
                result = intervieweeMapper.updateOfferResult(ids, 2);

                for (Integer intervieweeId : ids) {
                    interviewee = intervieweeMapper.getIntervieweeById(intervieweeId);
                    if (interviewee == null) {
                        hasError = true;
                        errorMsg.add("offer超时处理时，应聘者ID为" + intervieweeId + "的应聘者不存在\n");
                        log.error("offer超时处理时，应聘者ID为 {} 的应聘者不存在", intervieweeId);
//                        throw new RuntimeException("该应聘者不存在");
                    }
                    UpdateInterviewStatusDTO updateInterviewStatusDTO = new UpdateInterviewStatusDTO();
                    List<Integer> intervieweeIds = new ArrayList<>();
                    intervieweeIds.add(intervieweeId);
                    updateInterviewStatusDTO.setIntervieweeIds(intervieweeIds);
                    updateInterviewStatusDTO.setInterviewStatus(7);
                    Integer r = intervieweeMapper.updateInterviewStatus(updateInterviewStatusDTO);
                    if (r == 0) {
                        hasError = true;
                        errorMsg.add("offer超时处理时，应聘者ID为" + intervieweeId + "的应聘者面试状态更新失败\n");
                        log.error("offer超时处理时，应聘者ID为 {} 的应聘者面试状态更新失败", intervieweeId);
//                        throw new RuntimeException("修改应聘者面试状态失败");
                    }
                    r = onboardingMapper.deleteOnboardingByIntervieweeId(intervieweeId);
                    if (r == 0) {
                        hasError = true;
                        errorMsg.add("offer超时处理时，应聘者ID为" + intervieweeId + "的待入职信息删除失败\n");
                        log.error("offer超时处理时，应聘者ID为 {} 的待入职信息删除失败", intervieweeId);
//                        throw new RuntimeException("删除待入职信息失败");
                    }
                    interviewees.add(interviewee);
                }

                ToEmail toEmail = new ToEmail();
                List<String> emails = new ArrayList<>();
                if (result == 0 || hasError) {
                    emails.add(username1);
                    toEmail.setTos(emails.toArray(new String[0]));
                    toEmail.setSubject("offer超时修改状态失败");
                    if (result == 0) {
                        toEmail.setContent("offer超时修改状态失败的ids: " + ids + "\n");
                        log.error("offer超时修改状态失败的ids： {}", ids);
                    }
                    if (hasError) {
                        toEmail.setContent(toEmail.getContent() != null ? toEmail.getContent() + "offer超时处理时出现错误，错误信息: " + errorMsg : "offer超时处理时出现错误，错误信息: " + errorMsg);
                    }
                    emailUtil.sendSimpleEmail(toEmail);
                } else {
                    emails = interviewees.stream()
                            .map(Interviewee::getEmail)
                            .collect(Collectors.toList());
                    toEmail.setTos(emails.toArray(new String[0]));
                    toEmail.setSubject("offer接受过期通知");
                    toEmail.setContent("您未在规定时间内回复是否接受offer，现以视您放弃！");
                    emailUtil.sendSimpleEmail(toEmail);
                }
                offset += pageSize;
            }
        }
    }

    /**
     * 查询所有未选择是否接受offer的记录
     *
     * @return 结果
     */
    @Override
    public PageBean findAllActiveOffers(int page, int pageSize) {
        PageHelper.startPage(page, pageSize);
        List<Offer> offers = intervieweeMapper.findAllActiveOffers(LocalDateTime.now());
        Page<Offer> p = (Page<Offer>) offers;
        return new PageBean(p.getTotal(), p.getResult());
    }

    /**
     * 处理超时未选择是否接受offer的记录
     *
     * @param id offerId
     */
    @Override
    @Transactional
    public void checkOfferExpiry(Integer id) {
        Offer offer = intervieweeMapper.getOfferById(id);
        if (offer.getResult() == 0) {
            List<Interviewee> interviewees = new ArrayList<>();
            List<String> errorMsg = new ArrayList<>();
            boolean hasError = false;
            Integer result = 0;
            // 更新状态
            result = intervieweeMapper.updateOfferResult(List.of(id), 2);

            Integer intervieweeId = offer.getIntervieweeId();
            Interviewee interviewee = intervieweeMapper.getIntervieweeById(intervieweeId);
            if (interviewee == null) {
                hasError = true;
                errorMsg.add("offer超时处理时，应聘者ID为" + intervieweeId + "的应聘者不存在\n");
                log.error("offer超时处理时，应聘者ID为 {} 的应聘者不存在", intervieweeId);
//                        throw new RuntimeException("该应聘者不存在");
            }
            UpdateInterviewStatusDTO updateInterviewStatusDTO = new UpdateInterviewStatusDTO();
            List<Integer> intervieweeIds = new ArrayList<>();
            intervieweeIds.add(intervieweeId);
            updateInterviewStatusDTO.setIntervieweeIds(intervieweeIds);
            updateInterviewStatusDTO.setInterviewStatus(7);
            Integer r = intervieweeMapper.updateInterviewStatus(updateInterviewStatusDTO);
            if (r == 0) {
                hasError = true;
                errorMsg.add("offer超时处理时，应聘者ID为" + intervieweeId + "的应聘者面试状态更新失败\n");
                log.error("offer超时处理时，应聘者ID为 {} 的应聘者面试状态更新失败", intervieweeId);
//                        throw new RuntimeException("修改应聘者面试状态失败");
            }
            r = onboardingMapper.deleteOnboardingByIntervieweeId(intervieweeId);
            if (r == 0) {
                hasError = true;
                errorMsg.add("offer超时处理时，应聘者ID为" + intervieweeId + "的待入职信息删除失败\n");
                log.error("offer超时处理时，应聘者ID为 {} 的待入职信息删除失败", intervieweeId);
//                        throw new RuntimeException("删除待入职信息失败");
            }
            interviewees.add(interviewee);

            ToEmail toEmail = new ToEmail();
            List<String> emails = new ArrayList<>();
            if (result == 0 || hasError) {
                emails.add(username1);
                toEmail.setTos(emails.toArray(new String[0]));
                toEmail.setSubject("offer超时修改状态失败");
                if (result == 0) {
                    toEmail.setContent("offer超时修改状态失败的id: " + id + "\n");
                    log.error("offer超时修改状态失败的ids： {}", id);
                }
                if (hasError) {
                    toEmail.setContent(toEmail.getContent() != null ? toEmail.getContent() + "offer超时处理时出现错误，错误信息: " + errorMsg : "offer超时处理时出现错误，错误信息: " + errorMsg);
                }
                emailUtil.sendSimpleEmail(toEmail);
                throw new RuntimeException(String.valueOf(errorMsg));
            } else {
                emails = interviewees.stream()
                        .map(Interviewee::getEmail)
                        .collect(Collectors.toList());
                toEmail.setTos(emails.toArray(new String[0]));
                toEmail.setSubject("offer接受过期通知");
                toEmail.setContent("您未在规定时间内回复是否接受offer，现以视您放弃！");
                emailUtil.sendSimpleEmail(toEmail);
            }
        }
    }
}
